package com.jyh.blog.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jyh.blog.dao.UserDao;
import com.jyh.blog.dao.UserInfoDao;
import com.jyh.blog.dto.OnlineUserDTO;
import com.jyh.blog.dto.UserDetailDTO;
import com.jyh.blog.entity.UserInfo;
import com.jyh.blog.entity.UserRole;
import com.jyh.blog.exception.MyException;
import com.jyh.blog.service.RedisService;
import com.jyh.blog.service.UserInfoService;
import com.jyh.blog.service.UserRoleService;
import com.jyh.blog.strategy.context.UploadStrategyContext;
import com.jyh.blog.utils.UserUtils;
import com.jyh.blog.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.session.SessionInformation;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

import static com.jyh.blog.constant.RedisPrefixConst.USER_CODE_KEY;
import static com.jyh.blog.enums.FilePathEnum.AVATAR;
import static com.jyh.blog.utils.PageUtils.getLimitCurrent;
import static com.jyh.blog.utils.PageUtils.getSize;

/**
 * (UserInfo)表服务实现类
 * @author jyh
 * @since 2023-02-13 16:25:15
 */
@Service("userInfoService")
public class UserInfoServiceImpl extends ServiceImpl<UserInfoDao, UserInfo> implements UserInfoService {

    @Autowired
    private UserDao userDao;
    @Autowired
    private UserRoleService userRoleService;
    @Autowired
    private RedisService redisService;
    @Autowired
    private UploadStrategyContext uploadStrategyContext;
    @Autowired
    private SessionRegistry sessionRegistry;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void editUserRole(UserRoleVO userRoleVO) {
        UserInfo userInfo = UserInfo.builder()
                .id(userRoleVO.getUserInfoId())
                .nickname(userRoleVO.getNickname())
                .build();
        this.updateById(userInfo);
        //user_id实际上是user_info_id
        userRoleService.remove(new LambdaQueryWrapper<UserRole>().eq(UserRole::getUserId, userInfo.getId()));
        //创建用户权限记录
        List<UserRole> userRoleList = userRoleVO.getRoleIdList().stream().map(roleId ->
                UserRole.builder()
                        .roleId(roleId)
                        .userId(userInfo.getId())
                        .build()
        ).collect(Collectors.toList());
        userRoleService.saveBatch(userRoleList);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void disableUser(UserDisableVO userDisableVO) {
        UserInfo userInfo = UserInfo.builder().id(userDisableVO.getUserInfoId())
                .isDisable(userDisableVO.getIsDisable())
                .build();
        this.updateById(userInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserInfo(UserInfoVO userInfoVO) {
        //根据登录用户，获取userInfo_id
        UserInfo userInfo = UserInfo.builder()
                .id(UserUtils.getLoginUser().getUserInfoId())
                .nickname(userInfoVO.getNickname())
                .webSite(userInfoVO.getWebSite())
                .intro(userInfoVO.getIntro())
                .build();
        this.updateById(userInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserEmail(EmailVO emailVO) {
        //更改时会先调用sendCode发送验证码，此时redis中有emailVo携带的邮箱对应的验证码
        if (!emailVO.getCode().equals(redisService.get(USER_CODE_KEY + emailVO.getEmail()).toString())) {
            throw new MyException("验证码错误");
        }
        //更新用户信息表
        UserInfo userInfo = UserInfo.builder()
                .id(UserUtils.getLoginUser().getUserInfoId())
                .email(emailVO.getEmail())
                .build();
        this.updateById(userInfo);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String changeAvatar(MultipartFile file) {
        String avatar = uploadStrategyContext.executeUploadStrategy(file, AVATAR.getPath());
        //更新用户头像
        this.updateById(
                UserInfo.builder()
                        .avatar(avatar)
                        .id(UserUtils.getLoginUser().getUserInfoId())
                        .build()
        );
        return avatar;
    }

    @Override
    public PageResult<OnlineUserDTO> onlineUserList(ConditionVO conditionVO) {
        // 获取security在线session
        List<OnlineUserDTO> userOnlineDTOList = sessionRegistry.getAllPrincipals().stream()
                .filter(item -> sessionRegistry.getAllSessions(item, false).size() > 0)
                .map(item -> JSON.parseObject(JSON.toJSONString(item), OnlineUserDTO.class))
                .filter(item -> StringUtils.isBlank(conditionVO.getKeywords()) || item.getNickname().contains(conditionVO.getKeywords()))
                .sorted(Comparator.comparing(OnlineUserDTO::getLastLoginTime).reversed())
                .collect(Collectors.toList());
        // 执行分页
        int fromIndex = getLimitCurrent().intValue();
        int size = getSize().intValue();
        int toIndex = userOnlineDTOList.size() - fromIndex > size ? fromIndex + size : userOnlineDTOList.size();
        List<OnlineUserDTO> userOnlineList = userOnlineDTOList.subList(fromIndex, toIndex);
        return new PageResult<>(userOnlineList, userOnlineDTOList.size());
    }

    @Override
    public void removeOnlineUser(String userInfoId) {
        // 获取用户session
        List<Object> userInfoList = sessionRegistry.getAllPrincipals().stream().filter(item -> {
            UserDetailDTO userDetailDTO = (UserDetailDTO) item;
            return userDetailDTO.getUserInfoId().equals(userInfoId);
        }).collect(Collectors.toList());
        List<SessionInformation> allSessions = new ArrayList<>();
        userInfoList.forEach(item -> allSessions.addAll(sessionRegistry.getAllSessions(item, false)));
        // 注销session
        allSessions.forEach(SessionInformation::expireNow);
    }

}

